package com.qunarmei.niotest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 *
 *  NIO  服务器  没有解决沾包问题
 */
public class NIOServer {


    static  Map<String,SocketChannel> clientmap = new HashMap<>();


    public static void main(String[] args) throws Exception{
        //创建一个serverSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //创建Selector
        Selector selector = Selector.open();

        //绑定端口6666，在服务端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));

        //设置非阻塞模式
        serverSocketChannel.configureBlocking(false);

        //将channel注册到selector中，关心事件为op_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //循环监听客户端连接
        while (true){
            //selector等待1s钟，如果没有事件发生则可以去做别的事情
            if(selector.select(1000)==0){
//                System.out.println("服务端等待了1s,没有事件发生");
                continue;
            }

            //如果>0，则得到selectionKeys集合，已经获取到关注的事件了，selectionKeys是关注事件的集合
            //通过selectionKeys反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            //遍历selectionKeys集合，使用迭代器
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()){
                SelectionKey key = iterator.next();

                //根据key对应的通道发生的事件做相应的处理
                //相当于有客户端连接,给该客户端生成一个socketchannel
                if(key.isAcceptable()){
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //设置为非阻塞
                    socketChannel.configureBlocking(false);
                    System.out.println("客户端连接成功，生成了一个socketchannel"+socketChannel.hashCode());
                    //将sockerchannel注册到selector，关注事件为read,同行关联一个buffer
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));


                    clientmap.put(UUID.randomUUID().toString() , socketChannel );

                }

                if(key.isReadable()){
                    //通过key反向获取socketChannel
                    SocketChannel channel = (SocketChannel)key.channel();

                    //获取到该channel关联的buffer
                    ByteBuffer buffer=ByteBuffer.allocate(2048);

                    channel.read(buffer);
                    buffer.flip();

                    String receivedmessage = new String(buffer.array());

                    System.out.println("客户端 :" + receivedmessage);

                    AtomicReference<String> sendkey =new AtomicReference<>();

                    clientmap.forEach( (mapkey,value)->{
                        if(channel == value){
                            sendkey.set(mapkey);
                        }
                    });


                    clientmap.forEach( (mapkey,value)->{

                        ByteBuffer wiiterbuffer=ByteBuffer.allocate(4096);
                        wiiterbuffer.clear();
                        System.out.println( "数据长度 ==" +  (sendkey+ ":" + receivedmessage).getBytes().length);
                        wiiterbuffer.put((sendkey+ ":" + receivedmessage).getBytes());
                        wiiterbuffer.flip();

                        try {
                            value.write(wiiterbuffer);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }


                    });

                }

                //手动从集合中移除当前的selectionkey,防止重复操作
                iterator.remove();

            }

        }
    }
}